package com.fr.data.impl;

import com.fr.base.FRContext;
import com.fr.base.Inter;
import com.fr.base.StringUtils;
import com.fr.base.cache.store.Status;
import com.fr.data.TableDataException;
import com.fr.data.core.db.ColumnInformation;
import com.fr.data.core.db.DBUtils;
import com.fr.data.core.db.dialect.Dialect;
import com.fr.data.core.db.dialect.DialectFactory;
import com.fr.data.core.db.dialect.MSSQLDialect;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

public abstract class TableDataAdapter
  implements Serializable
{
  protected Set registedDBTableData;
  protected DatabaseConnection database;
  protected String sql;
  protected int resultIndexOfOut;
  protected transient Connection connection;
  protected transient Statement statement;
  protected transient ResultSet resultSet;
  protected transient boolean isCheckRowOver;
  protected transient ColumnInformation[] columnInformations;
  protected Status status;
  protected transient Dialect dialect;
  protected transient int shortcutRowCount;

  protected TableDataAdapter()
  {
    this(null, null, 0);
  }

  protected TableDataAdapter(DatabaseConnection paramDatabaseConnection, String paramString, int paramInt)
  {
    this.registedDBTableData = new HashSet();
    this.isCheckRowOver = false;
    this.columnInformations = null;
    this.dialect = null;
    this.shortcutRowCount = -1;
    this.status = Status.STATUS_UNINITIALISED;
    this.database = paramDatabaseConnection;
    this.sql = paramString;
    this.resultIndexOfOut = paramInt;
    this.status = Status.STATUS_ALIVE;
    dealSQLCharset();
  }

  private void dealSQLCharset()
  {
    if ((StringUtils.isNotBlank(this.database.getOriginalCharsetName())) && (StringUtils.isNotBlank(this.database.getNewCharsetName())))
      try
      {
        this.sql = new String(this.sql.getBytes(this.database.getNewCharsetName()), this.database.getOriginalCharsetName());
      }
      catch (UnsupportedEncodingException localUnsupportedEncodingException)
      {
        FRContext.getLogger().log(Level.WARNING, localUnsupportedEncodingException.getMessage(), localUnsupportedEncodingException);
      }
  }

  public final synchronized void register(DBTableData paramDBTableData)
  {
    this.registedDBTableData.add(paramDBTableData);
  }

  public final synchronized void unRegister(DBTableData paramDBTableData)
  {
    this.registedDBTableData.remove(paramDBTableData);
  }

  public int getColumnCount()
    throws TableDataException
  {
    if (this.columnInformations == null)
      initConnectionAndResultAndCheckInColumns();
    return this.columnInformations.length;
  }

  public String getColumnName(int paramInt)
    throws TableDataException
  {
    if (this.columnInformations == null)
      initConnectionAndResultAndCheckInColumns();
    return this.columnInformations[paramInt].getColumnName();
  }

  protected abstract void initRowValueStatus();

  protected synchronized void initConnectionAndResultAndCheckInColumns()
    throws TableDataException
  {
    if (this.connection != null)
      return;
    initRowValueStatus();
    try
    {
      Object localObject;
      if (this.database == null)
        throw new TableDataException(Inter.getLocText("Utils-Connection_can_not_be_null"));
      this.connection = this.database.createConnection();
      if (this.connection == null)
        throw new TableDataException(Inter.getLocText("Utils-Can_not_create_connection") + ":" + this.database.toString());
      FRContext.getLogger().log(Level.INFO, "SQL:\n" + this.sql);
      if (DBUtils.isProcedure(this.sql))
      {
        localObject = DBUtils.remoteProcedureCall(this.connection, this.sql, this.resultIndexOfOut);
        this.statement = ((Statement)localObject[0]);
        this.resultSet = ((ResultSet)localObject[1]);
      }
      else
      {
        if (this.dialect == null)
          this.dialect = DialectFactory.generateDialect(this.connection);
        localObject = DialectFactory.generateDialect(this.connection);
        if (localObject instanceof MSSQLDialect)
        {
          this.statement = this.connection.prepareCall(this.sql);
          this.resultSet = ((CallableStatement)this.statement).executeQuery();
        }
        else
        {
          this.statement = this.connection.createStatement();
          if (((Dialect)localObject).getFetchSize() > 0)
            this.statement.setFetchSize(((Dialect)localObject).getFetchSize());
          this.resultSet = this.statement.executeQuery(this.sql);
        }
      }
      if (this.columnInformations == null)
        this.columnInformations = DBUtils.checkInColumnInformationByMetaData(this.resultSet.getMetaData());
    }
    catch (Exception localException1)
    {
      try
      {
        releaseConnection();
      }
      catch (Exception localException2)
      {
      }
      throw new TableDataException("Query:" + this.sql + "\n" + localException1.getMessage(), localException1);
    }
  }

  /**
   * @deprecated
   */
  protected synchronized void checkInColumn()
    throws TableDataException
  {
    if (this.columnInformations != null)
      return;
    Connection localConnection = null;
    try
    {
      localConnection = this.database.createConnection();
      this.columnInformations = DBUtils.checkInColumnInformation(localConnection, this.sql, this.resultIndexOfOut);
    }
    catch (Exception localException)
    {
      throw new TableDataException("Query: \"" + this.sql + "\"\n" + localException.getMessage(), localException);
    }
    finally
    {
      if (localConnection != null)
        try
        {
          localConnection.close();
        }
        catch (SQLException localSQLException)
        {
          FRContext.getLogger().log(Level.INFO, localSQLException.getMessage(), localSQLException);
        }
    }
  }

  protected int shortcutGetRowCount()
  {
    if (this.shortcutRowCount == -1)
    {
      Connection localConnection = null;
      try
      {
        localConnection = this.database.createConnection();
        if (this.dialect == null)
          this.dialect = DialectFactory.generateDialect(localConnection);
        String str = this.dialect.getCountSql(this.sql);
        Statement localStatement = localConnection.createStatement();
        ResultSet localResultSet = localStatement.executeQuery(str);
        localResultSet.next();
        this.shortcutRowCount = localResultSet.getInt(1);
        localResultSet.close();
        localStatement.close();
      }
      catch (Exception localException)
      {
        this.shortcutRowCount = -2147483648;
      }
      finally
      {
        if (localConnection != null)
          try
          {
            localConnection.close();
          }
          catch (SQLException localSQLException)
          {
            FRContext.getLogger().log(Level.WARNING, localSQLException.getMessage(), localSQLException);
          }
      }
    }
    return this.shortcutRowCount;
  }

  public abstract int getRowCount()
    throws TableDataException;

  public abstract Object getValueAt(int paramInt1, int paramInt2)
    throws TableDataException;

  protected abstract boolean hasRow(int paramInt)
    throws TableDataException;

  public final synchronized void tryDestroy()
    throws SQLException
  {
    if (this.registedDBTableData.isEmpty())
      destroy();
  }

  private final synchronized void destroy()
    throws SQLException
  {
    if (this.status != Status.STATUS_SHUTDOWN)
    {
      release();
      this.status = Status.STATUS_SHUTDOWN;
    }
  }

  protected void release()
    throws SQLException
  {
    releaseConnection();
  }

  protected synchronized void releaseConnection()
    throws SQLException
  {
    if (this.connection != null)
    {
      if (this.resultSet != null)
        this.resultSet.close();
      if (this.statement != null)
        this.statement.close();
      this.connection.close();
      this.connection = null;
      this.statement = null;
      this.resultSet = null;
    }
  }

  public synchronized void finalize()
    throws Throwable
  {
    super.finalize();
    destroy();
  }
}